/*
 * Copyright (C) 2022-2024, Xiaohua Semiconductor Co., Ltd.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-04-28     CDT          first version
 * 2024-06-11     CDT          remove CLK_Delay for usb, as it is already included in ddl API
 */

#include "board.h"
#include "board_config.h"
#include "hc32f460.h"
#include "hc32f460_sram.h"
#include "hc32f460_efm.h"
#include "hc32_ll_clk.h"
#include "hc32_ll_pwc.h"
/* unlock/lock peripheral */
#define EXAMPLE_PERIPH_WE               (LL_PERIPH_GPIO | LL_PERIPH_EFM | LL_PERIPH_FCG | \
                                         LL_PERIPH_PWC_CLK_RMU | LL_PERIPH_SRAM | LL_PERIPH_LVD)
#define EXAMPLE_PERIPH_WP               (LL_PERIPH_EFM | LL_PERIPH_FCG | LL_PERIPH_SRAM)

/** System Base Configuration
*/

//-----------------------------------------------
//函数功能: CPU统时钟内部晶振系初始化函数
//
//参数: 	Type[in]		ePowerOnMode:正常上电  ePowerDownMode:低功耗
//                    
//返回值:  	无
//
//备注:   120M主频
//-----------------------------------------------
void api_MCU_XTALSTOPSysClockInit()
{
    stc_clk_sysclk_cfg_t    stcSysClkCfg;
    stc_clk_xtal_cfg_t      stcXtalCfg;
    stc_clk_mpll_cfg_t      stcMpllCfg;
    stc_sram_config_t       stcSramConfig;
    stc_clk_xtal_stp_cfg_t    stcXtalStpCfg;

    if( CLK_GetFlagStatus(ClkFlagXTALStoppage) == Set)//切换到内部晶振运行
    {
        CLK_MpllCmd(Disable);
        CLK_XtalCmd(Disable);
        /* Disable xtal fault dectect and occur reset. */
        stcXtalStpCfg.enDetect = Disable;
        stcXtalStpCfg.enMode = ClkXtalStpModeInt;
        stcXtalStpCfg.enModeInt = Disable;
        stcXtalStpCfg.enModeReset = Disable;
        CLK_XtalStpConfig(&stcXtalStpCfg);
        CLK_ClearXtalStdFlag();

        MEM_ZERO_STRUCT(stcSysClkCfg);
        MEM_ZERO_STRUCT(stcXtalCfg);
        MEM_ZERO_STRUCT(stcMpllCfg);
        MEM_ZERO_STRUCT(stcSramConfig);
        MEM_ZERO_STRUCT(stcXtalStpCfg);
        /* Set bus clk div. */
        stcSysClkCfg.enHclkDiv  = ClkSysclkDiv1;//100 ,max 200MHz
        stcSysClkCfg.enExclkDiv = ClkSysclkDiv2;//50 ,max 100MHz
        stcSysClkCfg.enPclk0Div = ClkSysclkDiv1;//100 ,max 200MHz
        stcSysClkCfg.enPclk1Div = ClkSysclkDiv1;//100 ,max 100MHz
        stcSysClkCfg.enPclk2Div = ClkSysclkDiv4;//25  ,max 60MHz
        stcSysClkCfg.enPclk3Div = ClkSysclkDiv4;//25 ,max 50MHz
        stcSysClkCfg.enPclk4Div = ClkSysclkDiv2;//50 ,max 100MHz
        CLK_SysClkConfig(&stcSysClkCfg);
    
        /* Config HRC and Enable Xtal */
        CLK_HrcCmd(Enable);
        

        
        /* sram init include read/write wait cycle setting */
        stcSramConfig.u8SramIdx = Sram12Idx | Sram3Idx | SramHsIdx | SramRetIdx;
        stcSramConfig.enSramRC = SramCycle2;
        stcSramConfig.enSramWC = SramCycle2;
        SRAM_Init(&stcSramConfig);
    
        /* flash read wait cycle setting */
        EFM_Unlock();
        EFM_SetLatency(EFM_LATENCY_5);
        EFM_Lock();
    
        /* MPLL config (XTAL / pllmDiv * plln / PllpDiv = 200M). */
        stcMpllCfg.pllmDiv = 1ul;
        stcMpllCfg.plln    = 25ul;    
        stcMpllCfg.PllpDiv = 4ul;
        stcMpllCfg.PllqDiv = 4ul;
        stcMpllCfg.PllrDiv = 4ul;
        CLK_SetPllSource(ClkPllSrcHRC);
        CLK_MpllConfig(&stcMpllCfg);
    
        /* Enable MPLL. */
        CLK_MpllCmd(Enable);
       
    }
    else
    {
        /* Disable xtal fault dectect and occur reset. */
        stcXtalStpCfg.enDetect = Disable;
        stcXtalStpCfg.enMode = ClkXtalStpModeInt;
        stcXtalStpCfg.enModeInt = Disable;
        stcXtalStpCfg.enModeReset = Disable;
        CLK_XtalStpConfig(&stcXtalStpCfg);
    }

}


void SystemBase_Config(void)
{
#if defined(BSP_USING_ON_CHIP_FLASH_CACHE)
    EFM_InstructionCacheCmd(1);
#endif
 

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{
  stc_clk_sysclk_cfg_t    stcSysClkCfg;
    stc_clk_xtal_cfg_t      stcXtalCfg;
    stc_clk_mpll_cfg_t      stcMpllCfg;
    stc_sram_config_t       stcSramConfig;
    stc_clk_xtal_stp_cfg_t    stcXtalStpCfg;
    

    MEM_ZERO_STRUCT(stcSysClkCfg);
    MEM_ZERO_STRUCT(stcXtalCfg);
    MEM_ZERO_STRUCT(stcMpllCfg);
    MEM_ZERO_STRUCT(stcSramConfig);
    MEM_ZERO_STRUCT(stcXtalStpCfg);
    /* Set bus clk div. */
    stcSysClkCfg.enHclkDiv  = ClkSysclkDiv1;    //160 ,max 200MHz
    stcSysClkCfg.enExclkDiv = ClkSysclkDiv2;    //80 ,max 100MHz
    stcSysClkCfg.enPclk0Div = ClkSysclkDiv1;    //160 ,max 200MHz 
    stcSysClkCfg.enPclk1Div = ClkSysclkDiv2;    //80 ,max 100MHz
    stcSysClkCfg.enPclk2Div = ClkSysclkDiv4;    //40  ,max 60MHz
    stcSysClkCfg.enPclk3Div = ClkSysclkDiv4;    //40 ,max 50MHz
    stcSysClkCfg.enPclk4Div = ClkSysclkDiv2;    //80 ,max 100MHz
    CLK_SysClkConfig(&stcSysClkCfg);

    /* Config Xtal and Enable Xtal */
    stcXtalCfg.enMode = ClkXtalModeOsc;
    stcXtalCfg.enDrv = ClkXtalLowDrv;
    stcXtalCfg.enFastStartup = Enable;
    CLK_XtalConfig(&stcXtalCfg);
    PWC_REG_Unlock(PWC_UNLOCK_CODE0);
    CLK_XtalCmd(Enable);
    
    /* Enable xtal fault dectect and occur reset. */
    stcXtalStpCfg.enDetect = Enable;
    stcXtalStpCfg.enMode = ClkXtalStpModeReset;
    stcXtalStpCfg.enModeInt = Disable;
    stcXtalStpCfg.enModeReset = Disable;
    CLK_XtalStpConfig(&stcXtalStpCfg);


    /* sram init include read/write wait cycle setting */
    stcSramConfig.u8SramIdx = Sram12Idx | Sram3Idx | SramHsIdx | SramRetIdx;
    stcSramConfig.enSramRC = SramCycle2;
    stcSramConfig.enSramWC = SramCycle2;
    SRAM_Init(&stcSramConfig);

    /* flash read wait cycle setting */
    EFM_Unlock();
    EFM_SetLatency(EFM_LATENCY_5);
    EFM_Lock();

    /* MPLL config (XTAL / pllmDiv * plln / PllpDiv = 200M). */
    stcMpllCfg.pllmDiv = 1ul;       //12M
    stcMpllCfg.plln    = 40ul;      //300
    stcMpllCfg.PllpDiv = 3ul;       //100
    stcMpllCfg.PllqDiv = 3ul;       //100
    stcMpllCfg.PllrDiv = 3ul;       //100
    CLK_SetPllSource(ClkPllSrcXTAL);
    CLK_MpllConfig(&stcMpllCfg);

    /* Enable MPLL. */
    CLK_MpllCmd(Enable);

    api_MCU_XTALSTOPSysClockInit();

    /* Wait MPLL ready. */
    while(Set != CLK_GetFlagStatus(ClkFlagMPLLRdy))
    {
        ;
    }
    /* Switch driver ability */
    PWC_HS2HP();
    /* Switch system clock source to MPLL. */
    CLK_SetSysClkSource(CLKSysSrcMPLL);
}

/** Peripheral Clock Configuration
*/
void PeripheralClock_Config(void)
{
#if defined(RT_USING_ADC)
//    CLK_SetPeriClockSrc(CLK_PERIPHCLK_PCLK);
#endif

#if defined(BSP_USING_USBD) || defined(BSP_USING_USBH)
    CLK_SetUSBClockSrc(CLK_USBCLK_PLLXP);
#endif
}

/** Peripheral Registers Unlock
*/
void PeripheralRegister_Unlock(void)
{
    LL_PERIPH_WE(EXAMPLE_PERIPH_WE);
}
